package cn.t.service.user;


import cn.t.constants.Constants;
import cn.t.core.exception.BizException;
import cn.t.core.mode.YesNoEnum;
import cn.t.core.service.ServiceImpl;
import cn.t.core.enums.base.BaseStatusEnum;
import cn.t.core.enums.base.CommonError;
import cn.t.enums.user.RoleTypeEnum;
import cn.t.model.user.ParticipantInfoDO;
import cn.t.model.user.RoleFirmDO;
import cn.t.model.user.RoleInfoDO;
import cn.t.repository.user.RoleInfoRepository;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import static cn.t.constants.Constants.REDIS_KEY__ROLE_INFO;


/**
 * 角色信息表领域服务
 *
 * @author l
 */
@Slf4j
@Service
@AllArgsConstructor
public class RoleInfoService extends ServiceImpl<RoleInfoDO, RoleInfoRepository> {

    public List<RoleInfoDO> fullFill(List<RoleInfoDO> roleInfoList) {
        if (roleInfoList == null || roleInfoList.isEmpty()) {
            return null;
        }
        return roleInfoList.stream().map(this::fullFill).collect(Collectors.toList());
    }

    public RoleInfoDO fullFill(RoleInfoDO roleInfo) {
        RoleInfoDO ret = findById(roleInfo.getId());
        if (ret == null || ret.getId() == null || !ret.getId().equals(roleInfo.getId())) {
            String errorMessage = String.format("指定的角色不存在 roleId=%s ", roleInfo.getId());
            log.error(errorMessage);
            throw new BizException(CommonError.ILLEGAL_PARAMETER, errorMessage);
        }

        return ret;
    }

    public List<RoleInfoDO> findByCode(String roleCode) {
        RoleInfoDO template = new RoleInfoDO();
        template.setRoleCode(roleCode);
        template.setStatus(String.valueOf(BaseStatusEnum.AVAILABLE.getCode()));
        template.setIsDeleted(YesNoEnum.FALSE);
        return repository.findByModel(template, 0, 1000, null, null);

    }

    @Override
    public RoleInfoDO findById(Long roleId) {
        String redisKey = String.format(REDIS_KEY__ROLE_INFO, roleId);
        RoleInfoDO roleInfoDO = (RoleInfoDO) redissonClient.getBucket(redisKey).get();

        if (roleInfoDO != null && roleId.equals(roleInfoDO.getId())) {
            return roleInfoDO;
        }

        roleInfoDO = repository.findById(roleId);
        List<RoleFirmDO> roleFirms = roleFirmService.findByRoleId(roleId);
        if (!CollectionUtils.isEmpty(roleFirms)) {
            List<Long> firmIds = roleFirms.stream().map(RoleFirmDO::getFirmId).collect(Collectors.toList());
            roleInfoDO.setFirmIds(firmIds);
        }

        redissonClient.getBucket(redisKey).set(roleInfoDO, 1, TimeUnit.HOURS);
        return roleInfoDO;
    }

    public List<RoleInfoDO> findAnonymousRoleByParticipantId(Long participantId) {
        RoleInfoDO template = new RoleInfoDO();
        template.setParticipantId(participantId);
        template.setRoleType(RoleTypeEnum.ANONYMOUS.getCode());
        template.setStatus(String.valueOf(BaseStatusEnum.AVAILABLE.getCode()));
        template.setIsDeleted(YesNoEnum.FALSE);
        return repository.findByModel(template, 0, 1000, null, null);
    }

    public void removeAnonymousRoleById(Collection<Long> roleIds) {
        RoleInfoDO template = new RoleInfoDO();
        template.setRoleIds(roleIds);
        template.setStatus(String.valueOf(BaseStatusEnum.AVAILABLE.getCode()));
        template.setIsDeleted(YesNoEnum.FALSE);
        List<RoleInfoDO> roleList = repository.findByModel(template, 0, roleIds.size(), null, null);
        if (CollectionUtils.isEmpty(roleList)) {
            return;
        }
        for (RoleInfoDO roleInfo : roleList) {
            if (RoleTypeEnum.ANONYMOUS.getCode().equals(roleInfo.getRoleType())
                    || RoleTypeEnum.MATERIAL_ANONYMOUS.getCode().equals(roleInfo.getRoleType())) {
                repository.deleteRoleById(roleInfo.getId());
            }
        }
    }

    public List<RoleInfoDO> createAnonymousRole(ParticipantInfoDO participantInfo) {

        List<RoleInfoDO> result = new ArrayList<>();

        RoleInfoDO roleInfo = new RoleInfoDO();
        roleInfo.setRoleName("Anonymous_PID_" + participantInfo.getId());
        roleInfo.setParticipantId(participantInfo.getId());
        roleInfo.setRoleType(RoleTypeEnum.ANONYMOUS.getCode());
        roleInfo.setStatus(String.valueOf(BaseStatusEnum.AVAILABLE.getCode()));
        roleInfo.setId(repository.addAndReturnId(roleInfo));
        result.add(roleInfo);

        RoleInfoDO material = new RoleInfoDO();
        material.setRoleName("material_anonymous_" + participantInfo.getId());
        material.setParticipantId(participantInfo.getId());
        material.setRoleType(RoleTypeEnum.MATERIAL_ANONYMOUS.getCode());
        material.setStatus(String.valueOf(BaseStatusEnum.AVAILABLE.getCode()));
        material.setGmtCreated(new Date());
        material.setId(repository.addAndReturnId(material));
        result.add(material);

        return result;
    }

    public void deleteRoleById(Long roleId) {
        repository.deleteRoleById(roleId);
    }

    public RoleInfoDO findByFirmAndId(Long firmId, Long roleId) {
        return repository.findByFirmAndId(firmId, roleId);
    }

    public List<RoleInfoDO> getRoleInfoByNameAndFirm(String roleName, Long firmId) {

        String redisKey = String.format(Constants.REDIS_KEY__ROLE_INFO__NAME_WITH_FIRM_ID, roleName, firmId);

        if (redissonClient.getBucket(redisKey).isExists()) {
            return (List<RoleInfoDO>) redissonClient.getBucket(redisKey).get();
        }

        List<RoleInfoDO> result = repository.getRoleInfoByNameAndFirm(roleName, firmId);
        if (!CollectionUtils.isEmpty(result)) {
            redissonClient.getBucket(redisKey).set(result, 5, TimeUnit.MINUTES);
        }

        return result;
    }

    public List<RoleInfoDO> findByType(Integer roleType) {
        RoleInfoDO template = new RoleInfoDO();
        template.setRoleType(roleType);
        template.setStatus(String.valueOf(BaseStatusEnum.AVAILABLE.getCode()));
        return repository.findByModel(template, 0, 1000, null, null);

    }

    @Autowired
    private RedissonClient redissonClient;

    @Autowired
    private RoleFirmService roleFirmService;


}
